//+------------------------------------------------------------------+
//|                          List.mqh 链表类头文件                   |
//|                版权所有 2000-2025, MetaQuotes Ltd.              |
//|                        官方网址: https://www.mql5.com            |
//+------------------------------------------------------------------+
#include <Object.h>  // 引入 CObject 基类头文件，CList 管理 CObject 及其派生类实例
//+------------------------------------------------------------------+
//| CList 类                                                         |
//| 功能：动态链表类，用于管理 CObject 及其派生类实例的链式存储与操作 |
//| 核心特性：                                                      |
//|  1. 支持对象的动态添加、插入、删除、排序、查找，无需预先指定容量  |
//|  2. 提供对象生命周期控制（m_free_mode 控制是否自动释放对象内存）  |
//|  3. 支持双向遍历（首/尾/前/后/当前节点），适配复杂链表操作场景     |
//| 继承关系：派生自 CObject 基类，可作为对象实例参与 MQL5 对象管理体系 |
//+------------------------------------------------------------------+
class CList : public CObject
  {
protected:
   CObject          *m_first_node;       // 指向链表第一个节点的指针（CObject 实例）
   CObject          *m_last_node;        // 指向链表最后一个节点的指针（CObject 实例）
   CObject          *m_curr_node;        // 指向链表当前遍历节点的指针（CObject 实例）
   int               m_curr_idx;         // 当前节点在链表中的索引（从 0 开始）
   int               m_data_total;       // 链表中节点（CObject 实例）的总数量
   bool              m_free_mode;        // 对象释放模式：true=删除节点时自动释放对象内存，false=仅移除节点引用
   bool              m_data_sort;        // 链表排序状态标记：true=已排序，false=未排序
   int               m_sort_mode;        // 排序模式（具体含义由 CObject::Compare 方法定义，通常 0=升序）

public:
   /**
    * @brief 构造函数：初始化 CList 链表实例
    * @details 初始化链表节点指针（首/尾/当前节点均为 NULL）、索引、计数、释放模式等成员变量，
    *          默认开启自动释放模式（m_free_mode=true），链表初始未排序（m_data_sort=false）
    */
                     CList(void);

   /**
    * @brief 析构函数：销毁 CList 链表实例
    * @details 调用 Clear 方法清空链表，根据 m_free_mode 决定是否释放所有节点对应的 CObject 实例内存
    */
                    ~CList(void);

   //--- 保护成员变量访问方法（只读/读写）
   /**
    * @brief 获取当前链表的对象释放模式
    * @return bool - 释放模式：true=删除节点时自动释放对象内存，false=仅移除节点引用（对象需外部管理）
    */
   bool              FreeMode(void)          const { return(m_free_mode);  }

   /**
    * @brief 设置链表的对象释放模式
    * @param mode [in] 释放模式：true=自动释放对象内存，false=仅移除节点引用（需外部手动管理对象生命周期）
    */
   void              FreeMode(bool mode)           { m_free_mode=mode;     }

   /**
    * @brief 获取链表中节点（CObject 实例）的总数量
    * @return int - 节点总数，空链表返回 0
    */
   int               Total(void)             const { return(m_data_total); }

   /**
    * @brief 检查链表是否已排序
    * @return bool - 排序状态：true=已排序（按 m_sort_mode 模式），false=未排序
    */
   bool              IsSorted(void)          const { return(m_data_sort);  }

   /**
    * @brief 获取链表当前的排序模式
    * @return int - 排序模式（具体规则由 CObject::Compare 方法定义，需与对象类的排序逻辑匹配）
    */
   int               SortMode(void)          const { return(m_sort_mode);  }

   //--- 对象类型识别方法
   /**
    * @brief 获取当前链表对象的类型标识（用于区分其他 CObject 派生类）
    * @return int - 类型标识，固定返回 0x7779（MQL5 链表类专属标识）
    */
   virtual int       Type(void) const { return(0x7779); }

   //--- 文件操作相关方法（链表整体序列化/反序列化）
   /**
    * @brief 将链表及其所有节点（CObject 实例）的数据写入指定文件
    * @details 先写入链表标识（0xFFFFFFFFFFFFFFFF）、类型、节点总数，再逐个调用节点的 Save 方法写入对象数据
    * @param file_handle [in] 已打开的文件句柄（需包含写入权限，建议用 FILE_BIN 二进制模式）
    * @return bool - 操作结果：true 表示链表及所有节点均写入成功，false 表示任一环节失败
    */
   virtual bool      Save(const int file_handle);

   /**
    * @brief 从指定文件读取数据并重建链表（含所有节点 CObject 实例）
    * @details 先验证链表标识、类型，再读取节点总数，通过 CreateElement 创建新对象并调用其 Load 方法加载数据
    * @param file_handle [in] 已打开的文件句柄（需包含读取权限，建议用 FILE_BIN 二进制模式）
    * @return bool - 操作结果：true 表示链表及所有节点均读取成功，false 表示任一环节失败
    */
   virtual bool      Load(const int file_handle);

   //--- 链表节点创建方法（需派生类重写，创建具体 CObject 派生类实例）
   /**
    * @brief 创建链表节点对应的 CObject 实例（纯虚函数逻辑，需用户在派生类中重写）
    * @details 基类默认返回 NULL，派生类需实现为创建具体对象（如 CMyObject *CreateElement() { return new CMyObject; }）
    * @return CObject* - 新创建的 CObject 实例指针；基类默认返回 NULL，必须在派生类中重写才能正常使用 Load 方法
    */
   virtual CObject  *CreateElement(void) { return(NULL); }

   //--- 链表填充相关方法（添加/插入节点）
   /**
    * @brief 向链表末尾添加一个 CObject 实例节点
    * @param new_node [in] 要添加的 CObject 实例指针（需确保指针有效，且对象未被其他链表管理）
    * @return int - 操作结果：成功返回新节点的索引（从 0 开始），失败返回 -1（如指针无效）
    */
   int               Add(CObject *new_node);

   /**
    * @brief 在链表指定索引位置插入一个 CObject 实例节点
    * @param new_node [in] 要插入的 CObject 实例指针（需确保指针有效）
    * @param index [in] 插入位置的索引（0 ≤ index ≤ Total()，超出范围则插入失败；index=-1 表示插入到当前节点位置）
    * @return int - 操作结果：成功返回插入位置的索引，失败返回 -1（如指针无效、索引越界）
    */
   int               Insert(CObject *new_node,int index);

   //--- 链表遍历与节点访问方法
   /**
    * @brief 根据 CObject 实例指针查找其在链表中的索引
    * @param node [in] 要查找的 CObject 实例指针（需确保指针有效）
    * @return int - 查找结果：找到时返回对应索引，未找到/指针无效返回 -1
    */
   int               IndexOf(CObject *node);

   /**
    * @brief 根据索引获取对应的 CObject 实例指针
    * @details 内部优化遍历逻辑（从当前节点、表头或表尾就近开始查找），提升访问效率
    * @param index [in] 节点索引（0 ≤ index < Total()）
    * @return CObject* - 查找结果：找到时返回对应实例指针，索引越界返回 NULL
    */
   CObject          *GetNodeAtIndex(int index);

   /**
    * @brief 获取链表第一个节点的 CObject 实例指针，并将当前节点定位到表头
    * @return CObject* - 表头节点指针，空链表返回 NULL
    */
   CObject          *GetFirstNode(void);

   /**
    * @brief 获取当前节点的前一个节点的 CObject 实例指针，并更新当前节点为前一个节点
    * @return CObject* - 当前节点的前一个节点指针，若当前节点是表头则返回 NULL
    */
   CObject          *GetPrevNode(void);

   /**
    * @brief 获取当前节点的 CObject 实例指针（不改变当前节点位置）
    * @return CObject* - 当前节点指针，未定位过节点（如空链表）返回 NULL
    */
   CObject          *GetCurrentNode(void);

   /**
    * @brief 获取当前节点的后一个节点的 CObject 实例指针，并更新当前节点为后一个节点
    * @return CObject* - 当前节点的后一个节点指针，若当前节点是表尾则返回 NULL
    */
   CObject          *GetNextNode(void);

   /**
    * @brief 获取链表最后一个节点的 CObject 实例指针，并将当前节点定位到表尾
    * @return CObject* - 表尾节点指针，空链表返回 NULL
    */
   CObject          *GetLastNode(void);

   //--- 链表节点删除方法
   /**
    * @brief 从链表中移除当前节点（仅移除引用，不释放对象内存），并返回被移除的节点指针
    * @return CObject* - 被移除的节点指针，当前节点无效（如空链表）返回 NULL
    */
   CObject          *DetachCurrent(void);

   /**
    * @brief 删除链表中的当前节点，并根据 m_free_mode 决定是否释放对象内存
    * @return bool - 操作结果：成功删除返回 true，当前节点无效（如空链表）返回 false
    */
   bool              DeleteCurrent(void);

   /**
    * @brief 根据索引删除链表中的节点，并根据 m_free_mode 决定是否释放对象内存
    * @param index [in] 要删除的节点索引（0 ≤ index < Total()）
    * @return bool - 操作结果：成功删除返回 true，索引越界返回 false
    */
   bool              Delete(int index);

   /**
    * @brief 清空链表中所有节点，根据 m_free_mode 决定是否释放所有对象内存
    * @details 从表头开始逐个删除节点，直至链表为空（m_data_total=0）
    */
   void              Clear(void);

   //--- 链表比较方法
   /**
    * @brief 比较当前链表与另一个链表是否完全相等（节点数量、对象内容均一致）
    * @details 需通过 CObject::Compare 方法判断两个节点对象是否相等（需对象类实现该方法）
    * @param List [in] 要比较的另一个 CList 实例指针（需确保指针有效）
    * @return bool - 比较结果：节点数量相同且所有对应节点对象相等返回 true，否则返回 false
    */
   bool              CompareList(CList *List);

   //--- 链表修改与排序方法
   /**
    * @brief 按指定模式对链表节点进行排序（基于 CObject::Compare 方法实现对象比较）
    * @param mode [in] 排序模式（具体规则由 CObject::Compare 方法定义，需与对象类逻辑匹配）
    */
   void              Sort(int mode);

   /**
    * @brief 将当前节点移动到链表指定索引位置
    * @param index [in] 目标索引位置（0 ≤ index < Total()）
    * @return bool - 操作结果：成功移动返回 true，索引越界/当前节点无效返回 false
    */
   bool              MoveToIndex(int index);

   /**
    * @brief 交换链表中两个节点的位置（仅调整节点引用关系，不改变对象本身）
    * @param node1 [in] 第一个要交换的 CObject 实例指针（需确保指针有效且属于当前链表）
    * @param node2 [in] 第二个要交换的 CObject 实例指针（需确保指针有效且属于当前链表）
    * @return bool - 操作结果：成功交换返回 true，指针无效/节点不属于当前链表返回 false
    */
   bool              Exchange(CObject *node1,CObject *node2);

   //--- 链表查找方法（仅适用于已排序链表）
   /**
    * @brief 在已排序链表中查找与目标对象匹配的节点（基于 CObject::Compare 方法实现匹配）
    * @param element [in] 目标 CObject 实例指针（用于匹配的基准对象，需确保指针有效）
    * @return CObject* - 查找结果：找到匹配节点返回对应指针，未找到/链表未排序返回 NULL
    */
   CObject          *Search(CObject *element);

protected:
   /**
    * @brief 快速排序算法：对链表指定范围节点按排序模式排序（内部使用，不对外暴露）
    * @details 基于 CObject::Compare 方法实现节点对象的大小比较，排序后更新 m_data_sort 和 m_sort_mode
    * @param beg [in] 排序范围的起始索引（0 ≤ beg ≤ end）
    * @param end [in] 排序范围的结束索引（beg ≤ end < Total()）
    * @param mode [in] 排序模式（与 CObject::Compare 方法的模式参数对应）
    */
   void              QuickSort(int beg,int end,int mode);

   /**
    * @brief 快速查找算法：在已排序链表中定位目标对象（内部使用，为 Search 方法提供支持）
    * @details 基于二分法实现，通过 CObject::Compare 方法判断对象匹配关系
    * @param element [in] 目标 CObject 实例指针（需确保指针有效）
    * @return CObject* - 查找结果：找到匹配节点返回对应指针，未找到返回 NULL
    */
   CObject          *QuickSearch(CObject *element);
  };
//+------------------------------------------------------------------+